﻿#include "data_type.h"

Matrix::Matrix()
{
}
Matrix::Matrix(vector<vector<double> >& _data_list)
{
	int i;

	i = 0;
	while (i < static_cast<int>(_data_list.size()))
	{
		data_list.push_back(_data_list[i]);
		i ++;
	}

	col_size = _data_list.size();
	row_size = _data_list[0].size();
}
Matrix::Matrix(vector<double>& _data_list)
{
	int i = 0;
	while (i < static_cast<int>(_data_list.size()))
	{
		vector<double> temp_vec;
		data_list.push_back(temp_vec);

		data_list[i].push_back(_data_list[i]);

		i ++;
	}

	col_size = _data_list.size();
	row_size = 1;
}
Matrix::Matrix(Vector& _vector)
{
	int i = 0;

	vector<double> temp_vec;
	while (i < _vector.size())
	{
		data_list.push_back(temp_vec);
		data_list[i].push_back(_vector.element(i));
		i ++;
	}

	col_size = _vector.size();
	row_size = 1;
}
Matrix::Matrix(const Matrix& _matrix)
{
	int i = 0, j = 0;

	while (i < _matrix.col())
	{
		data_list.push_back(_matrix.data_list[i]);
		i ++;
	}
	col_size = _matrix.col_size;
	row_size = _matrix.row_size;
}
Matrix::Matrix(vector<double>& _data_list, bool is_row)
{
	if(is_row)
	{
		data_list.push_back(_data_list);
		col_size = 1;
		row_size = _data_list.size();
	}
	else
	{
		int i = 0;
		while (i < static_cast<int>(_data_list.size()))
		{
			vector<double> temp_vec;
			data_list.push_back(temp_vec);

			data_list[i].push_back(_data_list[i]);

			i ++;
		}
		col_size = _data_list.size();
		row_size = 1;
	}
}
Matrix::Matrix(int _row, int _col)
{
	vector<double> temp_vec(_row, 0); // row 개 만큼 0 들을 집어 넣는다.
	data_list.assign(_col, temp_vec);

	row_size = _row;
	col_size = _col;
}
vector<double>& Matrix::operator[](int i)
{
	return data_list[i];
}

void Matrix::swap_row(int i, int j)
{
	int small = (i < j ? i : j);
	int big = (i > j ? i : j);

	if(big >= col_size)
	{
		int i = col_size;
		while ( i <= big )
		{
			vector<double> temp_vec(row_size, 0);
			data_list.push_back(temp_vec);
			i ++;
		}
		col_size = big + 1;
	}

	data_list[big].swap(data_list[small]);
}
void Matrix::swap_col(int i, int j)
{
	int small = (i < j ? i : j);
	int big = (i > j ? i : j);

	if(big >= row_size)
	{
		for(int i = 0; i < col_size; i ++)
		{
			data_list[i].insert(data_list[i].end(), big - row_size + 1, 0);
		}
		row_size = big + 1;
	}

	double temp;
	for(int i = 0; i < col_size; i++)
	{
		temp = data_list[i][small];
		data_list[i][small] = data_list[i][big];
		data_list[i][big] = temp;
	}

}

void Matrix::copy_row(int from, int to)
{
	int big = (from > to ? from : to);
	if(big >= col_size)
	{
		int i = col_size;
		while ( i <= big )
		{
			vector<double> temp_vec(row_size, 0);
			data_list.push_back(temp_vec);
			i ++;
		}
		col_size = big + 1;
	}
	for(int i = 0; i < row_size; i++)
	{
		data_list[to][i] = data_list[from][i];
	}
}
void Matrix::copy_col(int from, int to)
{
	int big = (from > to ? from : to);
	if(big >= row_size)
	{
		for(int i = 0; i < col_size; i ++)
		{
			data_list[i].insert(data_list[i].end(), big - row_size + 1, 0);
		}
		row_size = big + 1;
	}
	for(int i = 0; i < col_size; i++)
	{
		data_list[i][to] = data_list[i][from];
	}
}

void Matrix::move_row(int from, int to)
{
	int big = (from > to ? from : to);
	if(big >= col_size)
	{
		int i = col_size;
		while ( i <= big )
		{
			vector<double> temp_vec(row_size, 0);
			data_list.push_back(temp_vec);
			i ++;
		}
		col_size = big + 1;
	}
	for(int i = 0; i < row_size; i++)
	{
		data_list[to][i] = data_list[from][i];
		data_list[from][i] = 0;
	}
}
void Matrix::move_col(int from, int to)
{
	int big = (from > to ? from : to);
	if(big >= row_size)
	{
		for(int i = 0; i < col_size; i ++)
		{
			data_list[i].insert(data_list[i].end(), big - row_size + 1, 0);
		}
		row_size = big + 1;
	}
	for(int i = 0; i < col_size; i++)
	{
		data_list[i][to] = data_list[i][from];
		data_list[i][from] = 0;
	}
}

void Matrix::resize(int row, int col)
{
	if(col != col_size)
		data_list.resize(col);

	for(int i = 0; i < col; i ++)
	{
		data_list[i].assign(row, 0);
	}

	col_size = col;
	row_size = row;
}
double Matrix::element(int i, int j) const
{
	return data_list[i][j];
}
Vector Matrix::column_Vector(int i)
{
	vector<double> data(col_size, 0);
	for(int j = 0; j < col_size; j ++)
	{
		data[j] = data_list[j][i];
	}

	Vector vec(data);
	return vec;
}
vector<double> Matrix::column_vec(int i)
{
	vector<double> data(col_size, 0);
	for(int j = 0; j < col_size; j ++)
	{
		data[j] = data_list[j][i];
	}
	return data;
}

double Matrix::determinant()
{
	if(row_size == 2)
	{
		return data_list[0][0]*data_list[1][1] - data_list[0][1]*data_list[1][0];
	}

	double sum = 0;
	int x, y;
	for(int i = 0; i < row_size; i ++)
	{
		Matrix temp(row_size - 1, row_size - 1);
		for(x = 0; x < row_size; x ++)
		{
			for(y = 0; y < row_size; y ++)
			{
				if(x < i && y < i)
				{
					temp.data_list[x][y] = data_list[x][y];
				}
				else if(x < i && y > i)
				{
					temp.data_list[x][y - 1] = data_list[x][y];
				}
				else if(x > i && y < i)
				{
					temp.data_list[x - 1][y] = data_list[x][y];
				}
				else if(x > i && y > i)
				{
					temp.data_list[x - 1][y - 1] = data_list[x][y];
				}
			}
		}
		sum = sum + data_list[i][0] * temp.determinant();
	}

	return sum;
}
double Matrix::det_opt()
{
	
}

void Matrix::add_row(int to, int from, double times)
{
	for(int i = 0; i < row_size; i++)
	{
		data_list[to][i] += data_list[from][i] * times;
	}
}
Matrix Matrix::operator* (const Matrix& operand)
{
	Matrix temp(operand.row_size, col_size);
	if(row_size == operand.col_size)
	{
		for(int row = 0; row < col_size; row ++)
		{
			for(int col = 0; col < operand.row_size; col ++)
			{
				double sum = 0;
				for(int i = 0; i < row_size; i ++)
				{
					sum = sum + data_list[row][i] * operand.data_list[i][col];
				}
				temp.data_list[row][col] = sum;
			}
		}
		return temp;
	}
	throw Error::Matrix_error(0);
}
Matrix Matrix::operator+ (const Matrix& operand)
{
	if(row_size == operand.row_size && col_size == operand.col_size)
	{
		Matrix temp(row_size, col_size);
		for(int i = 0; i < col_size; i ++)
		{
			for(int j = 0; j < row_size; j ++)
			{
				temp[i][j] = data_list[i][j] + operand.data_list[i][j];
			}
		}

		return temp;
	}
	else
		throw Error::Matrix_error(0);
}
Matrix Matrix::operator- (Matrix& operand)
{
	if(row_size == operand.row_size && col_size == operand.col_size)
	{
		Matrix temp(row_size, col_size);
		for(int i = 0; i < col_size; i ++)
		{
			for(int j = 0; j < row_size; j ++)
			{
				temp[i][j] = data_list[i][j] - operand.data_list[i][j];
			}
		}

		return temp;
	}
	throw Error::Matrix_error(0);
}
ostream& operator<< (ostream& os, const Matrix& matrix)
{
	for(int i = 0; i < matrix.col_size; i++)
	{
		for(int j = 0; j < matrix.row_size; j++)
		{
			cout << matrix.data_list[i][j] << " ";
		}
		cout << endl;
	}

	return os;
}